package com.ecoolex.hotel.saas.core.manager;

import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.util.BeanUtil;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.common.util.DateUtil;
import com.ecoolex.framework.common.util.StringUtil;
import com.ecoolex.hotel.saas.core.dao.PresaleCouponDAO;
import com.ecoolex.hotel.saas.entity.PresaleCoupon;
import com.ecoolex.hotel.saas.entity.PresaleCoupon.Column;
import com.ecoolex.hotel.saas.entity.PresaleCouponExample;
import com.ecoolex.hotel.saas.entity.PresaleCouponExample.Criteria;
import com.ecoolex.hotel.saas.enums.PresaleCouponDistributionSettleType;
import com.ecoolex.hotel.saas.enums.PresaleCouponStatus;
import com.ecoolex.hotel.saas.pojo.EditPresaleCouponOneStepDTO;
import com.ecoolex.hotel.saas.pojo.EditPresaleCouponStep;
import com.ecoolex.hotel.saas.pojo.EditPresaleCouponThreeStepDTO;
import com.ecoolex.hotel.saas.pojo.EditPresaleCouponTwoStepDTO;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.script.ScriptEngine;

@Service
public class PresaleCouponManager {
	
    @Autowired
    private PresaleCouponDAO dao;
    
    @Autowired
    private PresaleCouponDistribtionManager presaleCouponDistribtionManager;
    
    @Autowired
    private PresaleCouponExpirydateManager presaleCouponExpirydateManager;
    
    @Autowired
    private PresaleCouponOrderManager presaleCouponOrderManager;
    
    public PresaleCoupon getPresaleCouponForUser(Integer preCouponId) {
    	PresaleCouponExample example = new PresaleCouponExample();
		Criteria criteria = example.createCriteria();
		criteria.andPreCouponIdEqualTo(preCouponId)
		.andStatusEqualTo(PresaleCouponStatus.ONLINE.real())
		.andDeletedEqualTo(PresaleCoupon.NOT_DELETED);
		return dao.selectOneByExampleWithBLOBs(example);
	}

	public Pagination<PresaleCoupon> queryPresaleCouponForUser(String name, Integer storeId, Integer categoryId, Page page) {
		return Pagination.create(page, 
			dao.count(name, storeId, categoryId,PresaleCouponStatus.ONLINE.real()),
			() -> dao.query(name, storeId, categoryId, PresaleCouponStatus.ONLINE.real(), page));
	}
    
    public PresaleCoupon getPresaleCoupon(Integer preCouponId) {
    	PresaleCouponExample example = new PresaleCouponExample();
		Criteria criteria = example.createCriteria();
		criteria.andPreCouponIdEqualTo(preCouponId).andDeletedEqualTo(PresaleCoupon.NOT_DELETED);
		return dao.selectOneByExampleWithBLOBs(example);
	}

	public Pagination<PresaleCoupon> queryPresaleCoupon(String name,Integer storeId, Page page) {
		PresaleCouponExample example = new PresaleCouponExample();
		Criteria criteria = example.createCriteria();
		if(Check.notNull(name)) {
			criteria.andNameLike("%"+name+"%");
		}
		criteria.andStoreIdEqualTo(storeId).andDeletedEqualTo(PresaleCoupon.NOT_DELETED);
		example.setOffset(page.getFirstIndex());
		example.setRows(page.getPageSize());
		example.orderBy(Column.createTime.desc());
		return Pagination.create(page, 
			dao.countByExample(example),
			() -> dao.selectByExample(example));
	}

	@Transactional
	public PresaleCoupon editPresaleCoupon(EditPresaleCouponStep step, String createUser){
		if(step instanceof EditPresaleCouponOneStepDTO) {
			return editOneStep((EditPresaleCouponOneStepDTO)step, createUser);
		}else if(step instanceof EditPresaleCouponTwoStepDTO) {
			return editTwoStep((EditPresaleCouponTwoStepDTO)step, createUser);
		}else if(step instanceof EditPresaleCouponThreeStepDTO) {
			return editThreeStep((EditPresaleCouponThreeStepDTO)step, createUser);
		}
		return null;
	}
	
	private PresaleCoupon editOneStep(EditPresaleCouponOneStepDTO one, String createUser) {
		BizAssert.isTrue(Check.notNull(one.getName()) && StringUtil.isIncludeTrimLength(one.getName(), 1, 50), 
			ResultCode.BIZ.build(1), 
			"预售券名称需1-50个字符");
		BizAssert.isTrue(Check.notNullAndGteZero(one.getRealPrice()),ResultCode.BIZ.build(2), "商品售价不能为空");
		BizAssert.isTrue(Check.notNullAndGteZero(one.getCounterPrice()),ResultCode.BIZ.build(3), "商品门市价不能为空");
		BizAssert.isTrue(Check.notNullAndGteZero(one.getStockNumber()),ResultCode.BIZ.build(4), "商品库存不能为空");
		// 发放时间
        BizAssert.isTrue(Check.notNull(one.getSaleStartTime()), ResultCode.BIZ.build(5), "开始销售时间不能为空");
        BizAssert.isTrue(Check.notNull(one.getSaleEndTime()), ResultCode.BIZ.build(6), "结束销售时间不能为空");
        DateUtil.cleanTimePart(one.getSaleStartTime());
        DateUtil.setMaxTimePart(one.getSaleEndTime());
        BizAssert.isTrue(Check.isLessThan(one.getSaleStartTime(), one.getSaleEndTime()),
            ResultCode.BIZ.build(7),
            "销售开始时间必须小于结束时间");
        BizAssert.isTrue(Check.isGreatThan(one.getSaleEndTime(), Date.from(Instant.now())),
            ResultCode.BIZ.build(8),
            "销售结束时间必须大于当前时间");
        PresaleCoupon presaleCoupon;
        //修改
		if(Check.notNullAndGtZero(one.getPreCouponId())) {
			presaleCoupon = getPresaleCoupon(one.getPreCouponId());
			BizAssert.isTrue(Check.notNull(presaleCoupon),
				ResultCode.BIZ.build(9),
				"预售券Id={}不存在", one.getPreCouponId());
			BizAssert.isTrue(Check.isGreatThanEqual(one.getStockNumber(), presaleCoupon.getUsedStockNumber()),ResultCode.BIZ.build(10), "商品总库存不能小于已使用库存");
			BeanUtil.copy(one, presaleCoupon);
			presaleCoupon.setUpdateUser(createUser);
			presaleCoupon.setUpdateTime(Date.from(Instant.now()));
			dao.updateByPrimaryKeySelective(presaleCoupon, Column.excludes(
				Column.storeId,
				Column.status,
				Column.deleted,
				Column.createUser,
				Column.createTime));
		}else {
			//新增
			presaleCoupon = new PresaleCoupon();
			BeanUtil.copy(one, presaleCoupon);
			presaleCoupon.setStatus(PresaleCouponStatus.EDITING.real());
			presaleCoupon.setUsedStockNumber(0);
			presaleCoupon.setSaleNumber(0);
			presaleCoupon.setDeleted(PresaleCoupon.NOT_DELETED);
			presaleCoupon.setCreateUser(createUser);
			presaleCoupon.setCreateTime(Date.from(Instant.now()));
			presaleCoupon.setUpdateUser(createUser);
			presaleCoupon.setUpdateTime(Date.from(Instant.now()));
			dao.insert(presaleCoupon);
		}
		return checkEdit(presaleCoupon);
	}
	
	private PresaleCoupon editTwoStep(EditPresaleCouponTwoStepDTO two, String createUser) {
		BizAssert.isTrue(Check.notNull(two.getPreCouponId()),ResultCode.BIZ.build(10), "预售券Id不存在");
		PresaleCoupon presaleCoupon = getPresaleCoupon(two.getPreCouponId());
		BizAssert.isTrue(Check.notNull(presaleCoupon),ResultCode.BIZ.build(11), "预售券不存在");
		BizAssert.isTrue(Check.notNull(two.getUseRule()) && StringUtil.isIncludeTrimLength(two.getUseRule(), 1, 500),
			ResultCode.BIZ.build(12), "使用规则必须1-500个字符");
		BizAssert.isTrue(Check.notNull(two.getRemark()) && StringUtil.isIncludeTrimLength(two.getRemark(), 1, 500),
			ResultCode.BIZ.build(13), "温馨提示必须1-500个字符");
		BeanUtil.copy(two, presaleCoupon);
		presaleCoupon.setUpdateUser(createUser);
		presaleCoupon.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeyWithBLOBs(presaleCoupon);
		return checkEdit(presaleCoupon);
	}

	private PresaleCoupon editThreeStep(EditPresaleCouponThreeStepDTO three, String createUser) {
		BizAssert.isTrue(Check.notNull(three.getPreCouponId()),ResultCode.BIZ.build(14), "预售券Id不存在");
		PresaleCoupon presaleCoupon = getPresaleCoupon(three.getPreCouponId());
		BizAssert.isTrue(Check.notNull(presaleCoupon),ResultCode.BIZ.build(15), "预售券不存在");
		//存在分销配置则结算方式不能为空
		if(Check.notNullOrEmpty(three.getDistributionIdList())) {
			BizAssert.isTrue(Check.notNull(three.getDistributionSettleType()),ResultCode.BIZ.build(16), "结算方式不能为空");
			if(three.getIsRefund().equals(1)) {
				BizAssert.isTrue(PresaleCouponDistributionSettleType.AFTER_PAY.notEqual(three.getDistributionSettleType()),
					ResultCode.BIZ.build(17),
					"商品可退款时，分佣结算方式不能选择【支付后】");
			}
		}
		//处理分销策略
		presaleCouponDistribtionManager.edit(three.getPreCouponId(), three.getDistributionIdList(), createUser);
		if(Check.notNull(three.getShareTitle())) {
			BizAssert.isTrue(StringUtil.isIncludeTrimLength(three.getShareTitle(), 1, 100),
				ResultCode.BIZ.build(18), "微信分享标题必须1-100个字符");
		}
		if(Check.notNull(three.getShareDescription())) {
			BizAssert.isTrue(StringUtil.isIncludeTrimLength(three.getShareDescription(), 1, 500),
				ResultCode.BIZ.build(19), "微信分享描述必须1-500个字符");
		}
		//处理有效期策略
		presaleCouponExpirydateManager.edit(three.getPreCouponId(), three.getExpirydateDTO(), createUser);
		presaleCoupon.setIsRefund(three.getIsRefund());
		presaleCoupon.setDistributionSettleType(three.getDistributionSettleType());
		presaleCoupon.setShareTitle(three.getShareTitle());
		presaleCoupon.setShareDescription(three.getShareDescription());
		presaleCoupon.setUpdateUser(createUser);
		presaleCoupon.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(presaleCoupon, 
			Column.isRefund,
			Column.distributionSettleType,
			Column.shareTitle,
			Column.shareDescription,
			Column.updateUser,
			Column.updateTime);
		return checkEdit(presaleCoupon);
	}
	
	private PresaleCoupon checkEdit(PresaleCoupon record) {
		if(Check.notEq(record.getStatus(), PresaleCouponStatus.EDITING.real())) {
			return record;
		}
		if(Check.isNull(record.getStoreId())) {
			return record;
		}else if(Check.isNull(record.getHeadImage())) {
			return record;
		}else if(Check.isNull(record.getIsRefund())) {
			return record;
		}
		record.setStatus(PresaleCouponStatus.EDITED.real());
		dao.updateByPrimaryKeySelective(record, Column.status);
		return record;
	}

	public PresaleCoupon onlinePresaleCoupon(PresaleCoupon record, String updateUser){
		record.setStatus(PresaleCouponStatus.ONLINE.real());
		record.setUpdateUser(updateUser);
		record.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(record, Column.status,Column.updateUser,Column.updateTime);
		return record;
	}

	public PresaleCoupon offlinePresaleCoupon(PresaleCoupon record, String updateUser){
		record.setStatus(PresaleCouponStatus.EDITED.real());
		record.setUpdateUser(updateUser);
		record.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(record, Column.status,Column.updateUser,Column.updateTime);
		return record;
	}

	@Transactional
	public Boolean delPresaleCoupon(PresaleCoupon record, String updateUser){
		record.setDeleted(PresaleCoupon.IS_DELETED);
		record.setUpdateUser(updateUser);
		record.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(record, Column.deleted,Column.updateUser,Column.updateTime);
		//删除关联的分销策略
		presaleCouponDistribtionManager.queryByPreCouponId(record.getPreCouponId()).forEach(r -> {
			presaleCouponDistribtionManager.delete(r, updateUser);
		});
		//删除关联的有效期策略
		presaleCouponExpirydateManager.delete(record.getPreCouponId(), updateUser);
		return true;
	}
	
	/**
	 * 下单时锁定库存
	 * @param preCouponId
	 * @param buyNumber
	 * @param updateUser
	 * @return
	 */
	public Boolean addUsedStockNumber(Integer preCouponId, Integer buyNumber, String updateUser) {
		return dao.addUsedStockNumber(preCouponId, buyNumber, updateUser) == 1;
	}
	
	/**
	 * 取消订单后释放库存
	 * @param preCouponId
	 * @param buyNumber
	 * @param updateUser
	 * @return
	 */
	public Boolean subtractUsedStockNumber(Integer preCouponId, Integer buyNumber, String updateUser) {
		return dao.subtractUsedStockNumber(preCouponId, buyNumber, updateUser) == 1;
	}
	
	/**
	 * 支付后增加销量
	 * @param preCouponId
	 * @param buyNumber
	 * @param updateUser
	 * @return
	 */
	public Boolean addSaleNumber(Integer preCouponId, Integer buyNumber, String updateUser) {
		return dao.addSaleNumber(preCouponId, buyNumber, updateUser) == 1;
	}
	
	/**
	 * 销售员可分佣金额
	 * @param preCouponId
	 * @param userId
	 * @return
	 */
	public BigDecimal salesUserCommissionAmt(Integer preCouponId, Integer storeId, Integer userId) {
		PresaleCoupon presaleCoupon = getPresaleCoupon(preCouponId);
		return presaleCouponOrderManager.calcCommission(userId, storeId, preCouponId, presaleCoupon.getRealPrice());
	}

	/**
	 * 查找销售日期过期的预授券
	 * @param size 获取的数量
	 * @return 预授权列表
	 */
	public List<PresaleCoupon> queryExpire(Integer size){
		PresaleCouponExample example = new PresaleCouponExample();
		Criteria criteria = example.createCriteria();
		criteria.andStatusEqualTo(PresaleCouponStatus.ONLINE.real()).andSaleEndTimeLessThanOrEqualTo(Date.from(Instant.now())).andDeletedEqualTo(PresaleCoupon.NOT_DELETED);
		example.limit(size);
		return dao.selectByExample(example);
	}
}